#include "serializer/serializer.h"

#include <gtest/gtest.h>

#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>

using namespace serializer;

/**
 * 通用往返序列化工具
 * 参数:
 * - value 输入值
 * - options 序列化选项
 * 返回值: 反序列化结果
 */
template <typename T>
T
roundtrip_via_cpo(const T & value, const default_options & options)
{
    vector_writer writer;
    serialize(writer, value, options);
    vector_reader reader(writer.data());
    return deserialize_cpo(reader, options, type_tag<T>);
}

TEST(cpo_associative_containers_test, map_and_unordered_map_roundtrip)
{
    default_options options{};

    std::map<int, std::string> mp{{1, "a"}, {2, "b"}, {3, "c"}};
    std::unordered_map<std::string, int> ump{{"x", 10}, {"y", 20}, {"z", 30}};

    auto mp_out = roundtrip_via_cpo(mp, options);
    auto ump_out = roundtrip_via_cpo(ump, options);

    EXPECT_EQ(mp_out, mp);
    EXPECT_EQ(ump_out.size(), ump.size());
    for (const auto & [k, v] : ump)
    {
        auto it = ump_out.find(k);
        ASSERT_NE(it, ump_out.end());
        EXPECT_EQ(it->second, v);
    }
}

TEST(cpo_associative_containers_test, set_and_unordered_set_roundtrip)
{
    default_options options{};

    std::set<int> st{1, 2, 3, 4};
    std::unordered_set<std::string> ust{"a", "b", "c"};

    auto st_out = roundtrip_via_cpo(st, options);
    auto ust_out = roundtrip_via_cpo(ust, options);

    EXPECT_EQ(st_out, st);
    EXPECT_EQ(ust_out.size(), ust.size());
    for (const auto & k : ust)
    {
        EXPECT_TRUE(ust_out.find(k) != ust_out.end());
    }
}

TEST(cpo_associative_containers_test, multimap_and_multiset_roundtrip)
{
    default_options options{};

    std::multimap<int, int> mmp{{1, 100}, {1, 200}, {2, 300}};
    std::multiset<int> mst{5, 5, 7, 7, 9};

    auto mmp_out = roundtrip_via_cpo(mmp, options);
    auto mst_out = roundtrip_via_cpo(mst, options);

    EXPECT_EQ(mmp_out, mmp);
    EXPECT_EQ(mst_out, mst);
}